package gui;

import gui.symbols.Symbol;
import gui.symbols.SymbolListCellRenderer;
import gui.symbols.SymbolListModel;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.HashMap;
import java.util.Map;

import javax.swing.ImageIcon;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.MatteBorder;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Document;

import qbfiles.QbFileHandler;
import qbfiles.QbParser;
import qbfiles.QbWriter;
import res.StringVars;
import core.ThActionListener;

public class MainWindow extends JFrame implements MouseListener{

  private static final long serialVersionUID = 1L;
  private JPanel jContentPane = null;
  private JScrollPane jIdentifierListScrollPane = null;
  private JMenuBar jThMenuBar = null;
  private JMenu jFileMenu = null;
  private JMenu jHelpMenu = null;
  private JMenuItem jFileMenuOpenItem = null;
  private JMenuItem jHelpMenuAboutItem = null;
  private ThActionListener listener;
  private JEditorPane jQbEditorPane = null;
  private JMenuItem jFileMenuSaveItem = null;
  private Map<Integer, String> fields = null;
  private JMenuItem jFileMenuImportSymbolItem = null;
  private JSplitPane mainSplitPane = null;
  private JSplitPane rightSplitPane = null;
  private JPanel mainSymbolPanel = null;
  private JPanel importedSymbolPanel = null;
  private JList mainSymbolList = null;
  private JList importedSymbolList = null;
  private SymbolListModel mainSymbolListModel = new SymbolListModel();
  private SymbolListModel importedSymbolListModel = new SymbolListModel();
  private Object symbolHighlight = null;
  private JMenuItem jFileMenuExitItem = null;
  
  /**
   * This is the default constructor
   */
  public MainWindow() {
    super();
    listener = new ThActionListener(this);
    initialize();
  }

  /**
   * This method initializes this
   * 
   * @return void
   */
  private void initialize() {
    this.setTitle(StringVars.WINDOW_NAME);
    this.setSize(800, 600);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setIconImage(Toolkit.getDefaultToolkit().getImage(getClass().getResource("/icons/thqbedit.png")));

    setLocationRelativeTo(null);
    
    this.setJMenuBar(getJThMenuBar());
    this.setContentPane(getJContentPane());
  }

  /**
   * This method initializes jContentPane
   * 
   * @return javax.swing.JPanel
   */
  private JPanel getJContentPane() {
    if (jContentPane == null) {
      jContentPane = new JPanel();
      jContentPane.setLayout(new BorderLayout());
      jContentPane.add(getMainSplitPane(), BorderLayout.CENTER);
      jContentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    }
    return jContentPane;
  }

  /**
   * This method initializes jIdentifierListScrollPane	
   * 	
   * @return javax.swing.JScrollPane	
   */
  private JScrollPane getJIdentifierListScrollPane() {
    if (jIdentifierListScrollPane == null) {
      jIdentifierListScrollPane = new JScrollPane();
      jIdentifierListScrollPane.setViewportView(getJQbEditorPane());
    }
    return jIdentifierListScrollPane;
  }

  /**
   * This method initializes jThMenuBar	
   * 	
   * @return javax.swing.JMenuBar	
   */
  private JMenuBar getJThMenuBar() {
    if (jThMenuBar == null) {
      jThMenuBar = new JMenuBar();
      jThMenuBar.add(getJFileMenu());
      jThMenuBar.add(getJHelpMenu());
    }
    return jThMenuBar;
  }

  /**
   * This method initializes jFileMenu	
   * 	
   * @return javax.swing.JMenu	
   */
  private JMenu getJFileMenu() {
    if (jFileMenu == null) {
      jFileMenu = new JMenu(StringVars.MENU_FILE);
      jFileMenu.add(getJFileMenuOpenItem());
      jFileMenu.add(getJFileMenuSaveItem());
      jFileMenu.add(getJFileMenuImportSymbolItem());
      jFileMenu.add(getJFileMenuExitItem());
      jFileMenu.setMnemonic('F');
    }
    return jFileMenu;
  }
  
  private JMenu getJHelpMenu() {
    if (jHelpMenu == null) {
      jHelpMenu = new JMenu(StringVars.MENU_HELP);
      jHelpMenu.add(getJHelpMenuAboutItem());
      jHelpMenu.setMnemonic('H');
    }
    return jHelpMenu;
  }

  /**
   * This method initializes jFileMenuOpenItem	
   * 	
   * @return javax.swing.JMenuItem	
   */
  private JMenuItem getJFileMenuOpenItem() {
    if (jFileMenuOpenItem == null) {
      jFileMenuOpenItem = new JMenuItem(StringVars.MENU_FILE_OPEN);
      jFileMenuOpenItem.addActionListener(listener);
      jFileMenuOpenItem.setActionCommand(ThActionListener.FILE_MENU_OPEN_ACTION);
      jFileMenuOpenItem.setMnemonic('O');
      jFileMenuOpenItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_MASK));
      jFileMenuOpenItem.setIcon(new ImageIcon(getClass().getResource("/icons/open.png")));
    }
    return jFileMenuOpenItem;
  }
  
  private JMenuItem getJHelpMenuAboutItem() {
    if (jHelpMenuAboutItem == null) {
      jHelpMenuAboutItem = new JMenuItem(StringVars.MENU_HELP_ABOUT);
      jHelpMenuAboutItem.addActionListener(listener);
      jHelpMenuAboutItem.setActionCommand(ThActionListener.HELP_MENU_ABOUT_ACTION);
      jHelpMenuAboutItem.setMnemonic('A');
      jHelpMenuAboutItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_MASK));
    }
    return jHelpMenuAboutItem;
  }
  
  /**
   * This method initializes jFileMenuSaveItem  
   *  
   * @return javax.swing.JMenuItem  
   */
  private JMenuItem getJFileMenuSaveItem() {
    if (jFileMenuSaveItem == null) {
      jFileMenuSaveItem = new JMenuItem(StringVars.MENU_FILE_SAVE);
      jFileMenuSaveItem.addActionListener(listener);
      jFileMenuSaveItem.setActionCommand(ThActionListener.FILE_MENU_SAVE_ACTION);
      jFileMenuSaveItem.setMnemonic('S');
      jFileMenuSaveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_MASK));
      jFileMenuSaveItem.setIcon(new ImageIcon(getClass().getResource("/icons/save.png")));
    }
    return jFileMenuSaveItem;
  }
  
  private Map<Integer, String> getFields(){
    if(fields == null){
      fields = new HashMap<Integer, String>();
    }
    return fields;
  }
  
  public void openFile(File fileToOpen){    
    QbFileHandler reader = new QbFileHandler(fileToOpen);
    QbParser parser = new QbParser(reader.getByteStream());
    parser.getTablePosition();
    reader.createTable();
    parser.setFields(reader.getFields());
    fields = reader.getFields();
    
    mainSymbolListModel.setFields(getFields());
    importedSymbolListModel.clear();
    symbolHighlight = null;
    
    listener.setHighlighterEnabled(false);
    getJQbEditorPane().setText(parser.parse());
    getJQbEditorPane().setCaretPosition(0);
    listener.setHighlighterEnabled(true);
        
    this.setTitle(StringVars.WINDOW_NAME + " - " + fileToOpen.toString());
  }
  
  public void saveFile(File fileToSaveTo){
    try {
      
      Document doc = getJQbEditorPane().getDocument();
      QbWriter writer = new QbWriter(doc.getText(0, doc.getLength()), fileToSaveTo, getFields());
      
      SaveProgress dialog = new SaveProgress(this, writer);
      dialog.execute();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
    
    this.setTitle(StringVars.WINDOW_NAME + " - " + fileToSaveTo.toString());
  }

  /**
   * This method initializes jQbEditorPane	
   * 	
   * @return javax.swing.JEditorPane	
   */
  private JEditorPane getJQbEditorPane() {
    if (jQbEditorPane == null) {
      jQbEditorPane = new JEditorPane();
      jQbEditorPane.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
      jQbEditorPane.addCaretListener(listener);
    }
    return jQbEditorPane;
  }

  /**
   * This method initializes jFileMenuImportSymbolItem	
   * 	
   * @return javax.swing.JMenuItem	
   */
  private JMenuItem getJFileMenuImportSymbolItem() {
    if (jFileMenuImportSymbolItem == null) {
      jFileMenuImportSymbolItem = new JMenuItem(StringVars.MENU_FILE_IMPORT_SYMBOLS);
      jFileMenuImportSymbolItem.addActionListener(listener);
      jFileMenuImportSymbolItem.setActionCommand(ThActionListener.FILE_MENU_IMPORT_SYMBOL_ACTION);
      jFileMenuImportSymbolItem.setMnemonic('I');
      jFileMenuImportSymbolItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, KeyEvent.CTRL_MASK));
      jFileMenuImportSymbolItem.setIcon(new ImageIcon(getClass().getResource("/icons/import.png")));
    }
    return jFileMenuImportSymbolItem;
  }
  
  private JMenuItem getJFileMenuExitItem() {
    if (jFileMenuExitItem == null) {
      jFileMenuExitItem = new JMenuItem(StringVars.MENU_FILE_EXIT);
      jFileMenuExitItem.addActionListener(listener);
      jFileMenuExitItem.setActionCommand(ThActionListener.FILE_MENU_EXIT_ACTION);
      jFileMenuExitItem.setMnemonic('E');
      jFileMenuExitItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.CTRL_MASK));
      jFileMenuExitItem.setIcon(new ImageIcon(getClass().getResource("/icons/exit.png")));
    }
    return jFileMenuExitItem;
  }
  
  private JPanel getMainSymbolPanel(){
    if(mainSymbolPanel == null){
      mainSymbolPanel = new JPanel(new BorderLayout());
      JLabel title = new JLabel(StringVars.LOCAL_SYMBOLS_TITLE);
      title.setOpaque(true);
      title.setBackground(new Color(190, 220, 255));
      title.setBorder(new MatteBorder(1, 1, 0, 1, Color.GRAY));
      
      mainSymbolPanel.add(title, BorderLayout.NORTH);
      mainSymbolPanel.add(new JScrollPane(getMainSymbolList()), BorderLayout.CENTER);
    }
    return mainSymbolPanel;
  }
  
  private JList getMainSymbolList(){
    if(mainSymbolList == null){
      mainSymbolList = new JList(mainSymbolListModel);
      mainSymbolList.setCellRenderer(new SymbolListCellRenderer());
      mainSymbolList.addMouseListener(this);
      mainSymbolList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    }
    return mainSymbolList;
  }
  
  private JPanel getImportedSymbolPanel(){
    if(importedSymbolPanel == null){
      importedSymbolPanel = new JPanel(new BorderLayout());
      JLabel title = new JLabel(StringVars.IMPORTED_SYMBOLS_TITLE);
      title.setOpaque(true);
      title.setBackground(new Color(190, 220, 255));
      title.setBorder(new MatteBorder(1, 1, 0, 1, Color.GRAY));
      
      importedSymbolPanel.add(title, BorderLayout.NORTH);
      importedSymbolPanel.add(new JScrollPane(getImportedSymbolList()), BorderLayout.CENTER);
    }
    return importedSymbolPanel;
  }
  
  private JList getImportedSymbolList(){
    if(importedSymbolList == null){
      importedSymbolList = new JList(importedSymbolListModel);
      importedSymbolList.setCellRenderer(new SymbolListCellRenderer());
      importedSymbolList.addMouseListener(this);
      importedSymbolList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    }
    return importedSymbolList;
  }
  
  private JSplitPane getRightSplitPane(){
    if(rightSplitPane == null){
      rightSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, getMainSymbolPanel(), getImportedSymbolPanel());
      rightSplitPane.setDividerLocation(400);
      rightSplitPane.setUI(new BasicSplitPaneUI() {
        @SuppressWarnings("serial")
        public BasicSplitPaneDivider createDefaultDivider(){
          return new BasicSplitPaneDivider(this){
            public void setBorder(Border b) {}
          };
        }
      });
      rightSplitPane.setBorder(null);
    }
    return rightSplitPane;
  }
  
  private JSplitPane getMainSplitPane(){
    if(mainSplitPane == null){
      mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, getJIdentifierListScrollPane(), getRightSplitPane());
      mainSplitPane.setDividerLocation(500);
      mainSplitPane.setUI(new BasicSplitPaneUI() {
        @SuppressWarnings("serial")
        public BasicSplitPaneDivider createDefaultDivider(){
          return new BasicSplitPaneDivider(this){
            public void setBorder(Border b) {}
          };
        }
      });
      mainSplitPane.setBorder(null);
    }
    return mainSplitPane;
  }
  
  public void importSymbols(Object[] symbolArray){
    for(Object o : symbolArray){
      if(o instanceof Symbol){
        Symbol s = (Symbol)o;
        if(!getFields().containsValue(s.getName())){
          getFields().put(s.getField(), s.getName());
          importedSymbolListModel.addField(s);
        }
      }
    }
  }
  
  private class SymbolHighlight extends DefaultHighlighter.DefaultHighlightPainter{
    public SymbolHighlight(){
      super(Color.ORANGE);
    }
  }

  public void mouseClicked(MouseEvent e) {
    try {
      if(e.getSource() == getMainSymbolList() || e.getSource() == getImportedSymbolList()){
        JList list = (JList)e.getSource();
        String s = ((Symbol)list.getSelectedValue()).getName();
        Document doc = getJQbEditorPane().getDocument();
        int index = doc.getText(0, doc.getLength()).indexOf(s, getJQbEditorPane().getCaretPosition() + 1);
        
        if(index == -1)
          index = doc.getText(0, doc.getLength()).indexOf(s);
        
        if(index != -1){
          getJQbEditorPane().setCaretPosition(index);
          if(symbolHighlight != null)
            getJQbEditorPane().getHighlighter().removeHighlight(symbolHighlight);
          symbolHighlight = getJQbEditorPane().getHighlighter().addHighlight(index, index + s.length(), new SymbolHighlight());
        }
      }
    }
    catch (Exception ex) {
      ex.printStackTrace();
    }
  }
  public void mouseEntered(MouseEvent e) {}
  public void mouseExited(MouseEvent e) {}
  public void mousePressed(MouseEvent e) {}
  public void mouseReleased(MouseEvent e) {}
}
